package com.clj.blesample.operation;


import android.app.ProgressDialog;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.graphics.Color;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import androidx.fragment.app.Fragment;

import com.clj.blesample.R;
import com.clj.blesample.entity.Record;
import com.clj.blesample.entity.Result;
import com.clj.blesample.udp.UdpClient;
import com.clj.fastble.BleManager;
import com.clj.fastble.callback.BleMtuChangedCallback;
import com.clj.fastble.callback.BleNotifyCallback;
import com.clj.fastble.callback.BleWriteCallback;
import com.clj.fastble.data.BleDevice;
import com.clj.fastble.exception.BleException;
import com.clj.fastble.utils.HexUtil;
import com.github.mikephil.charting.charts.LineChart;
import com.github.mikephil.charting.components.Legend;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.LineDataSet;
import com.github.mikephil.charting.highlight.Highlight;
import com.github.mikephil.charting.listener.OnChartValueSelectedListener;
import com.github.mikephil.charting.utils.ColorTemplate;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Executors;

import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

public class RecordFragment extends Fragment implements UdpClient.OnDataReceiveListener, OnChartValueSelectedListener {

    private List<BluetoothGattCharacteristic> characteristicList = new ArrayList<>();
    private Button btnStartRecord;
    private Button btnUpload;
    private View svLog;
    private Button showLog;
    private BluetoothGattCharacteristic mNotifyCharacteristic;
    private BluetoothGattCharacteristic mWriteCharacteristic;
    private BleDevice mBleDevice;
    private BluetoothGattService mConnectService;
    private TextView txt;
    private boolean isRecording = false;
    private final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    private StringBuffer sb = new StringBuffer();
    private String mData = null;
    private final List<Record> records = new ArrayList<>();
    private final long sleepTime = 5000L;
    private LineChart chart;
    private ProgressDialog mProgressDialog;
    private Timer timer;

    public static RecordFragment newInstance() {
        Bundle args = new Bundle();
        RecordFragment fragment = new RecordFragment();
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fragment_record, null);
        initView(v);
        return v;
    }

    private void initView(View v) {
        btnStartRecord = v.findViewById(R.id.startRecord);
        btnUpload = v.findViewById(R.id.btnUpload);
        showLog = v.findViewById(R.id.showLog);
        chart = v.findViewById(R.id.chart);
        txt = v.findViewById(R.id.tvLog);
        svLog = v.findViewById(R.id.svLog);
        initChart();
        initBleData();
        connectUdp();
        btnUpload.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                addText(txt, "记录结束~");
                stopRecord();
                saveData(mData);
            }
        });
        btnStartRecord.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                startRecord();
            }
        });
        showLog.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                showLog.setSelected(!showLog.isSelected());
                if (showLog.isSelected()) {
                    showLog.setText("查看图表");
                    svLog.setVisibility(View.VISIBLE);
                    chart.setVisibility(View.INVISIBLE);
                } else {
                    showLog.setText("查看日志");
                    svLog.setVisibility(View.INVISIBLE);
                    chart.setVisibility(View.VISIBLE);
                }
            }
        });
    }

    private void initChart() {
        chart.setOnChartValueSelectedListener(this);

        // no description text
        chart.getDescription().setEnabled(false);

        // enable touch gestures
        chart.setTouchEnabled(true);

        chart.setDragDecelerationFrictionCoef(0.9f);
        chart.setNoDataText("暂无数据");
        chart.setNoDataTextColor(Color.BLACK);
        // enable scaling and dragging
        chart.setDragEnabled(true);
        chart.setScaleEnabled(true);
        chart.setDrawGridBackground(false);
        chart.setHighlightPerDragEnabled(true);

        // if disabled, scaling can be done on x- and y-axis separately
        chart.setPinchZoom(true);

        // set an alternative background color
        chart.setBackgroundColor(Color.WHITE);
        chart.animateX(200);

        // get the legend (only possible after setting data)
        Legend l = chart.getLegend();

        // modify the legend ...
        l.setForm(Legend.LegendForm.LINE);
        l.setTextSize(11f);
        l.setTextColor(Color.BLACK);
        l.setVerticalAlignment(Legend.LegendVerticalAlignment.BOTTOM);
        l.setHorizontalAlignment(Legend.LegendHorizontalAlignment.LEFT);
        l.setOrientation(Legend.LegendOrientation.HORIZONTAL);
        l.setDrawInside(false);
//        l.setYOffset(11f);

        XAxis xAxis = chart.getXAxis();
        xAxis.setTextSize(11f);
        xAxis.setTextColor(Color.BLACK);
        xAxis.setDrawGridLines(false);
        xAxis.setDrawAxisLine(false);

        YAxis leftAxis = chart.getAxisLeft();
        leftAxis.setTextColor(ColorTemplate.getHoloBlue());
        leftAxis.setAxisMaximum(70f);
        leftAxis.setAxisMinimum(0f);
        leftAxis.setDrawGridLines(true);
        leftAxis.setGranularityEnabled(true);

        YAxis rightAxis = chart.getAxisRight();
        rightAxis.setTextColor(Color.RED);
        rightAxis.setAxisMaximum(50f);
        rightAxis.setAxisMinimum(0f);
        rightAxis.setDrawGridLines(false);
        rightAxis.setDrawZeroLine(false);
        rightAxis.setGranularityEnabled(false);
    }

    private void showChartData(List<Record> records) {
        ArrayList<Entry> values1 = new ArrayList<>();
        ArrayList<Entry> values2 = new ArrayList<>();

        for (int i = 0; i < records.size(); i++) {
            Record record = records.get(i);
            float voltage = record.voltage;
            float electric = record.electric;
            values1.add(new Entry(i, voltage));
            values2.add(new Entry(i, electric));
        }

        LineDataSet set1, set2;

        if (chart.getData() != null &&
                chart.getData().getDataSetCount() > 0) {
            set1 = (LineDataSet) chart.getData().getDataSetByIndex(0);
            set2 = (LineDataSet) chart.getData().getDataSetByIndex(1);
            set1.setValues(values1);
            set2.setValues(values2);
            chart.getData().notifyDataChanged();
            chart.notifyDataSetChanged();
        } else {
            // create a dataset and give it a type
            set1 = new LineDataSet(values1, "电压");

            set1.setAxisDependency(YAxis.AxisDependency.LEFT);
            set1.setColor(ColorTemplate.getHoloBlue());
            set1.setCircleColor(Color.BLACK);
            set1.setLineWidth(2f);
            set1.setCircleRadius(3f);
            set1.setFillAlpha(65);
            set1.setFillColor(ColorTemplate.getHoloBlue());
            set1.setHighLightColor(Color.rgb(244, 117, 117));
            set1.setDrawCircleHole(false);
            set2 = new LineDataSet(values2, "电流");
            set2.setAxisDependency(YAxis.AxisDependency.RIGHT);
            set2.setColor(Color.RED);
            set2.setCircleColor(Color.BLACK);
            set2.setLineWidth(2f);
            set2.setCircleRadius(3f);
            set2.setFillAlpha(65);
            set2.setFillColor(Color.RED);
            set2.setDrawCircleHole(false);
            set2.setHighLightColor(Color.rgb(244, 117, 117));

            // create a data object with the data sets
            LineData data = new LineData(set1, set2);
            data.setValueTextColor(Color.BLACK);
            data.setValueTextSize(9f);

            // set data
            chart.setData(data);
        }
    }

    private void connectUdp() {
        UdpClient.getInstance().setOnDataReceiveListener(this);
        UdpClient.getInstance().connect("47.111.144.84", 10010);
    }


    public void initBleData() {
        mBleDevice = ((DetailActivity) getActivity()).getBleDevice();

        BleManager.getInstance().setMtu(mBleDevice, 200, new BleMtuChangedCallback() {
            @Override
            public void onSetMTUFailure(final BleException exception) {
                requireActivity().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        addText(txt, "mtu设置失败" + exception);
                    }
                });
            }

            @Override
            public void onMtuChanged(int mtu) {
                requireActivity().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        addText(txt, "mtu设置成功");
                    }
                });
            }
        });

        BluetoothGatt gatt = BleManager.getInstance().getBluetoothGatt(mBleDevice);


        for (BluetoothGattService service : gatt.getServices()) {
            if (service.getUuid().toString().startsWith("0000ffa0")) {
                mConnectService = service;
            }
        }
        if (mConnectService == null) {
            Toast.makeText(requireContext(), "未找到对应0000ffa0-0000-1000-8000-00805f9b34fb的蓝牙服务", Toast.LENGTH_LONG).show();
            return;
        }
        characteristicList.clear();
        characteristicList.addAll(mConnectService.getCharacteristics());
        for (BluetoothGattCharacteristic characteristic : characteristicList) {
            if (characteristic.getUuid().toString().startsWith("0000ffa1")) {
                int charaProp = characteristic.getProperties();
                if ((charaProp & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) > 0) {
                    mWriteCharacteristic = characteristic;
                }
                if ((charaProp & BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
                    mNotifyCharacteristic = characteristic;
                }
            }
        }
        if (mNotifyCharacteristic == null) {
            Toast.makeText(requireContext(), "未找到Notify特征:0000ffa1-0000-1000-8000-00805f9b34fb", Toast.LENGTH_LONG).show();
            return;
        }
        if (mWriteCharacteristic == null) {
            Toast.makeText(requireContext(), "未找到Write特征:0000ffa1-0000-1000-8000-00805f9b34fb", Toast.LENGTH_LONG).show();
            return;
        }
    }

    private void startRecord() {
        btnUpload.setVisibility(View.GONE);
        records.clear();
        isRecording = true;
        mData = null;
        sb = new StringBuffer();
        btnStartRecord.setText("正在记录焊接数据...");
        btnStartRecord.setEnabled(false);
        startNotify();
        startWrite();
    }

    private void stopRecord() {
        isRecording = false;
        stopNotify();
        btnStartRecord.setText("重新焊接");
        btnStartRecord.setEnabled(true);
    }

    private void startWrite() {
        Executors.newSingleThreadExecutor().submit(new Runnable() {
            @Override
            public void run() {
                while (isRecording) {
                    writeData("01030076000225D1");
                    try {
                        Thread.sleep(sleepTime);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

            }
        });
    }


    private void startNotify() {
        if (mBleDevice == null || mConnectService == null || mNotifyCharacteristic == null) {
            Toast.makeText(requireContext(), "未找到Notify特征:0000ffa1-0000-1000-8000-00805f9b34fb", Toast.LENGTH_LONG).show();
            return;
        }
        BleManager.getInstance().notify(
                mBleDevice,
                mConnectService.getUuid().toString(),
                mNotifyCharacteristic.getUuid().toString(),
                new BleNotifyCallback() {

                    @Override
                    public void onNotifySuccess() {
                        requireActivity().runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                addText(txt, "notify success");
                            }
                        });
                    }

                    @Override
                    public void onNotifyFailure(final BleException exception) {
//                        runOnUiThread(new Runnable() {
//                            @Override
//                            public void run() {
//                                addText(txt, exception.toString());
//                            }
//                        });
                    }

                    @Override
                    public void onCharacteristicChanged(byte[] data) {
                        final String result = HexUtil.formatHexString(data);
                        try {
                            if (result.startsWith("0103")) {
//                                if (sb.length() == 0) {
                                addText(txt, "接收到数据:" + result);
                                String voltage = result.substring(6, 10);
                                String electric = result.substring(10, 14);
                                final String time = format.format(System.currentTimeMillis());
                                final float v = Integer.parseInt(voltage, 16) / 10f;
                                final float e = Integer.parseInt(electric, 16) / 10f;
                                records.add(new Record(v, e, time));
                                getActivity().runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        addText(txt, "接收到电压:" + v + "，电流：" + e + "，时间：" + time);
                                        showChartData(new ArrayList<>(records.size() >= 20 ? records.subList(records.size() - 20, records.size()) : records));
                                    }
                                });
//                                }
                            } else if (result.startsWith("1480")) {
//                                isRecording = false;
                                if (TextUtils.isEmpty(mData)) {
                                    if (sb.length() == 0) {
                                        sb.append(result);
                                    } else {
                                        mData = sb.toString();
                                        final String no = mData.substring(4, 12);
                                        final String rNo = mData.substring(12, 20);
                                        getActivity().runOnUiThread(new Runnable() {
                                            @Override
                                            public void run() {
                                                addText(txt, "接收到数据:" + mData);
                                                addText(txt, "接收到焊机编号：" + no + "，记录编号：" + rNo + "，时间：" + format.format(System.currentTimeMillis()));
                                                btnUpload.setVisibility(View.VISIBLE);
//                                                addText(txt, "记录结束~");
//                                                stopRecord();
//                                                saveData(mData);
                                            }
                                        });

                                    }
                                }

                            } else {
                                sb.append(result);
                            }
                        } catch (Exception e) {
                            getActivity().runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    addText(txt, "接收到格式异常的数据：" + result);
                                }
                            });
                        }
                    }
                });
    }

    private void saveData(String data) {
        showProgress("正在上传数据...");
        //UDP获取结束指令
        addText(txt, "udp send:" + data);
        UdpClient.getInstance().sendByteCmd(HexUtil.hexStringToBytes(data), 1001);
        uploadData();
    }

    private void showProgress(String content) {
        if (mProgressDialog == null) {
            mProgressDialog = new ProgressDialog(requireContext());
        }
        mProgressDialog.setMessage(content);
        mProgressDialog.show();
    }

    private void hideProgress() {
        if (mProgressDialog != null && mProgressDialog.isShowing()) {
            mProgressDialog.cancel();
        }
    }


    private void uploadData() {
        Executors.newCachedThreadPool().execute(new Runnable() {
            @Override
            public void run() {
                try {
                    Gson gson = new Gson();
                    String json = gson.toJson(records);
                    final String no = mData.substring(4, 12);
                    final String rNo = mData.substring(12, 20);
                    String fileName = Integer.parseInt(no, 16) + "_" + Integer.parseInt(rNo, 16) + ".json";
                    File cacheFile = new File(requireContext().getCacheDir(), fileName);
                    if (cacheFile.exists()) {
                        cacheFile.delete();
                    }
                    BufferedWriter bfw = new BufferedWriter(new FileWriter(cacheFile, true));
                    bfw.write(json);
                    bfw.newLine();
                    bfw.flush();
                    bfw.close();
                    RequestBody body = new MultipartBody.Builder()
                            .setType(MultipartBody.FORM)
                            .addFormDataPart("file", fileName, RequestBody.create(MediaType.parse("application/octet-stream"), cacheFile))
                            .build();

                    Request request = new Request.Builder()
                            .url("http://47.111.144.84:82/FileUpload")
                            .post(body)
                            .build();
                    OkHttpClient client = new OkHttpClient();
                    final Response response = client.newCall(request).execute();
                    if (response.code() == 200) {
                        //上传成功
                        String resultJson = response.body().string();
                        final Result<String> result = gson.fromJson(resultJson, new TypeToken<Result<String>>() {
                        }.getType());
                        getActivity().runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                if (result.code == 200) {
                                    Toast.makeText(requireContext(), "数据上传成功", Toast.LENGTH_SHORT).show();
                                    addText(txt, "数据上传成功");
                                } else {
                                    addText(txt, "数据上传失败，" + result.info);
                                    Toast.makeText(requireContext(), "数据上传失败，" + result.info, Toast.LENGTH_SHORT).show();
                                }
                                hideProgress();
                            }
                        });
                    } else {
                        getActivity().runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                Toast.makeText(requireContext(), "数据上传失败，" + response.code(), Toast.LENGTH_SHORT).show();
                                addText(txt, "数据上传失败:" + response.code());
                                hideProgress();
                            }
                        });
                    }
                } catch (final IOException e) {
                    getActivity().runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Toast.makeText(requireContext(), "数据上传失败，" + e, Toast.LENGTH_SHORT).show();
                            addText(txt, "数据上传失败:" + e);
                            hideProgress();
                        }
                    });
                }
            }
        });
    }


    private void stopNotify() {
        if (mBleDevice == null || mConnectService == null || mNotifyCharacteristic == null) {
            Toast.makeText(requireContext(), "未找到Notify特征:0000ffa1-0000-1000-8000-00805f9b34fb", Toast.LENGTH_LONG).show();
            return;
        }
        BleManager.getInstance().stopNotify(
                mBleDevice,
                mNotifyCharacteristic.getService().getUuid().toString(),
                mNotifyCharacteristic.getUuid().toString());
    }

    private void writeData(String hex) {
        BleManager.getInstance().write(
                mBleDevice,
                mWriteCharacteristic.getService().getUuid().toString(),
                mWriteCharacteristic.getUuid().toString(),
                HexUtil.hexStringToBytes(hex),
                new BleWriteCallback() {

                    @Override
                    public void onWriteSuccess(final int current, final int total, final byte[] justWrite) {
                        getActivity().runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                addText(txt, "写入成功: " + current
                                        + " total: " + total
                                        + " justWrite: " + HexUtil.formatHexString(justWrite, true));
                            }
                        });
                    }

                    @Override
                    public void onWriteFailure(final BleException exception) {
                        getActivity().runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                addText(txt, "写入异常：" + exception.toString());
                            }
                        });
                    }
                });
    }


    private void addText(TextView textView, String content) {
        textView.append(content);
        textView.append("\n");
        int offset = textView.getLineCount() * textView.getLineHeight();
        if (offset > textView.getHeight()) {
            textView.scrollTo(0, offset - textView.getHeight());
        }
    }

    @Override
    public void onConnectSuccess() {
        addText(txt, "udp连接成功");
        //开始发心跳包
//        startHeartbeatTimer();
    }

    @Override
    public void onConnectFail() {
        addText(txt, "udp连接失败");
    }

    @Override
    public void onDataReceive(byte[] buffer, int size, int requestCode) {
        if (requestCode == 1001) {
            addText(txt, "接收到udp数据：" + HexUtil.formatHexString(buffer));
            writeData(HexUtil.formatHexString(buffer));
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        UdpClient.getInstance().disconnect();
        stopRecord();
    }

    @Override
    public void onValueSelected(Entry e, Highlight h) {
        chart.centerViewToAnimated(e.getX(), e.getY(), chart.getData().getDataSetByIndex(h.getDataSetIndex())
                .getAxisDependency(), 500);
    }

    @Override
    public void onNothingSelected() {

    }

    private static final long TIME_OUT = 120 * 1000;
    private static final long HEARTBEAT_MESSAGE_DURATION = 10 * 1000;

    /**
     * 启动心跳，timer 间隔十秒
     */
    private void startHeartbeatTimer() {
        if (timer == null) {
            timer = new Timer();
        } else {
            timer.cancel();
        }
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                UdpClient.getInstance().sendByteCmd(HexUtil.hexStringToBytes("1480"), 1000);
            }
        }, HEARTBEAT_MESSAGE_DURATION);
    }
}
